package com.atguigu.tingshu.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.Buckets;
import co.elastic.clients.elasticsearch._types.aggregations.LongTermsBucket;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import co.elastic.clients.json.JsonData;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.rep.AlbuminfoRep;
import com.atguigu.tingshu.search.rep.SuggestRep;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbuminfoRep albuminfoRep;

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private SuggestRep suggestRep;

    @Autowired
    private RedisTemplate redisTemplate;


    private static final String ES_INDEX = "albuminfo";
    private static final String SUGGESTION = "suggestinfo";


    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String dimension) {

        String key = RedisConstant.RANKING_KEY_PREFIX + category1Id;

        Boolean flage = redisTemplate.opsForHash().hasKey(key, dimension);

        if(flage){
            List<AlbumInfoIndex> list = (List)redisTemplate.opsForHash().get(key, dimension);
            return list;
        }

        return null;
    }

    @Override
    public void updateLatelyAlbumRanking() {
        try {
            // 获取所有一级分类
            List<BaseCategory1> baseCategory1List = albumFeignClient.findAllCategory1().getData();

            Assert.notNull(baseCategory1List,"获取所有一级分类id失败");

            List<Long> category1Ids = baseCategory1List.stream().map(BaseCategory1::getId).collect(Collectors.toList());

            // 构建语句并查询
            String [] rankingDimensionArray = {"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};

            for (Long category1Id : category1Ids) {
                for (String rankingDimension : rankingDimensionArray) {
                    SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(s -> s.index(ES_INDEX)
                                    .query(q -> q.term(t -> t.field("category1Id").value(category1Id)))
                                    .size(10)
                                    .sort(sort -> sort.field(f -> f.field(rankingDimension).order(SortOrder.Desc)))
                            , AlbumInfoIndex.class);
                    // 解析数据，并存入 redis中
                    List<Hit<AlbumInfoIndex>> hits = searchResponse.hits().hits();

                    Assert.notNull(hits,"es查询语句失败");

                    List<AlbumInfoIndex> albumInfoIndexList = hits.stream().map(hit -> hit.source()).collect(Collectors.toList());

                    String key = RedisConstant.RANKING_KEY_PREFIX + category1Id;
                    redisTemplate.opsForHash().put(key,rankingDimension,albumInfoIndexList);
                }
            }
        }catch (Exception e){
            log.error("[搜索服务]更新排行榜异常：{}", e);
            throw new RuntimeException(e);
        }
    }


    @Override
    public void upperAlbum(Long albumId) {

        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();

        // 使用CompletableFuture 实现异步任务
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
            Assert.notNull(albumInfo, "专辑不存在，专辑ID{}", albumId);

            BeanUtil.copyProperties(albumInfo, albumInfoIndex);

            // 封装album_attribute_value
            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
            // 实体类转换
            List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueVoList.stream().map(albumAttributeValue -> {
                AttributeValueIndex attributeValueIndex = BeanUtil.copyProperties(albumAttributeValue, AttributeValueIndex.class);
                return attributeValueIndex;
            }).collect(Collectors.toList());
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
            return albumInfo;
        },threadPoolExecutor);



        CompletableFuture<Void> basecategoryViewCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            // 封装一二三级分类
            BaseCategoryView baseCategoryView = albumFeignClient.getCategoryView(albumInfo.getCategory3Id()).getData();
            Assert.notNull(baseCategoryView, "分类不存在，分类ID{}", albumInfo.getCategory3Id());
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());

        },threadPoolExecutor);

        CompletableFuture<Void> userInfoCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(albumInfo.getUserId()).getData();
            Assert.notNull(userInfoVo, "主播信息不存在，主播ID：{}", albumInfo.getUserId());
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
        },threadPoolExecutor);


        CompletableFuture<Void> statCompletableFuture = CompletableFuture.runAsync(() -> {
            //5.TODO 封装统计信息，采用产生随机值 以及专辑热度
            //5.1 随机为专辑产生播放量，订阅量，购买量，评论量 、
            int num1 = RandomUtil.randomInt(1000, 2000);
            int num2 = RandomUtil.randomInt(500, 1000);
            int num3 = RandomUtil.randomInt(200, 400);
            int num4 = RandomUtil.randomInt(100, 200);
            albumInfoIndex.setPlayStatNum(num1);
            albumInfoIndex.setSubscribeStatNum(num2);
            albumInfoIndex.setBuyStatNum(num3);
            albumInfoIndex.setCommentStatNum(num4);

            albumInfoIndex.setCreateTime(DateTime.now().toString());   // 这一步很重要，否则时间格式对不上
        },threadPoolExecutor);

        //6.组合异步任务对象-需求以上四个异步任务必须全部执行完毕，主线程继续
        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                statCompletableFuture,
                basecategoryViewCompletableFuture,
                userInfoCompletableFuture
        ).join();

        //6.将索引库文档对象存入索引库
        albumInfoIndex.setCreateTime(DateTime.now().toString());
        albuminfoRep.save(albumInfoIndex);


        // 添加提词
        this.saveSuggestIndex(albumInfoIndex);

        // 把 albumId 添加到布隆过滤器
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);

        log.info("专辑上架成功,专辑上架id:{}",albumInfoIndex.getId());
    }

    /**
     * 关键字
     * @param albumInfoIndex
     */
    private void saveSuggestIndex(AlbumInfoIndex albumInfoIndex) {
        SuggestIndex suggestIndex = new SuggestIndex();

        suggestIndex.setId(albumInfoIndex.getId().toString());
        suggestIndex.setTitle(albumInfoIndex.getAlbumTitle());

        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinyinUtil.getPinyin(albumInfoIndex.getAlbumTitle(),"")}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinyinUtil.getFirstLetter(albumInfoIndex.getAlbumTitle(),"")}));
        suggestRep.save(suggestIndex);
    }



    @Override
    public List<String> completeSuggest(String keyword) {
        // 构建语句，查询题词库
        try {
            SearchResponse<SuggestIndex> searchResponse = elasticsearchClient.search(s -> s.index(SUGGESTION)
                            .suggest(
                                    s1 -> s1.suggesters("mySuggestKeyword", fs -> fs.prefix(keyword).completion(co -> co.field("keyword").size(10).skipDuplicates(true)))
                                            .suggesters("mySuggestPinyin", fs -> fs.prefix(keyword).completion(co -> co.field("keywordPinyin").size(10).skipDuplicates(true)))
                                            .suggesters("mySuggestSequence", fs -> fs.prefix(keyword).completion(co -> co.field("keywordSequence").size(10).skipDuplicates(true)))
                            )
                    , SuggestIndex.class);

            // 解析数据,并封装
            Set<String> hashSet = new LinkedHashSet<>();

            hashSet.addAll(this.parseSuggestResult(searchResponse.suggest().get("mySuggestKeyword")));
            hashSet.addAll(this.parseSuggestResult(searchResponse.suggest().get("mySuggestPinyin")));
            hashSet.addAll(this.parseSuggestResult(searchResponse.suggest().get("mySuggestSequence")));

            // 假如数据大于等于10 就直接返回，否者用 match 补全
            if (hashSet.size() >= 10) return new ArrayList<>(hashSet).subList(0,10);


            SearchResponse<AlbumInfoIndex> albumInfoIndexSearchResponse = elasticsearchClient.search(s -> s.index(ES_INDEX).query(q -> q.match(m -> m.field("albumTitle").query(keyword))), AlbumInfoIndex.class);
            // 解析结果集
            List<Hit<AlbumInfoIndex>> hits = albumInfoIndexSearchResponse.hits().hits();
            if(CollectionUtil.isNotEmpty(hits)){
                for (Hit<AlbumInfoIndex> hit : hits) {
                    String albumTitle = hit.source().getAlbumTitle();
                    hashSet.add(albumTitle);
                    if(hashSet.size() >= 10) break;
                }
            }

            return new ArrayList<>(hashSet);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private Collection<String> parseSuggestResult(List<Suggestion<SuggestIndex>> mySuggestKeyword) {

        // 遍历获取自动补全对象
        List<String> list = new ArrayList<>();
        for (Suggestion<SuggestIndex> suggestIndexSuggestion : mySuggestKeyword) {
            List<CompletionSuggestOption<SuggestIndex>> options = suggestIndexSuggestion.completion().options();
            if(CollectionUtil.isNotEmpty(options)){
                for (CompletionSuggestOption<SuggestIndex> option : options) {
                    String title = option.source().getTitle();
                    list.add(title);
                }
            }

        }
        return list;
    }


    @Override
    public void lowerAlbum(Long albumId) {
        albuminfoRep.deleteById(albumId);
    }

    @Override
    @SneakyThrows
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {

        // 封装查询语句
        SearchRequest request = this.buildDSL(albumIndexQuery);

        System.out.println("生成的语句:" + request.toString());

        // 执行查询语句
        SearchResponse<AlbumInfoIndex> search = elasticsearchClient.search(request, AlbumInfoIndex.class);

        // 封装结果集
        AlbumSearchResponseVo albumSearchResponseVo = this.parseRuslt(search,albumIndexQuery);

        return albumSearchResponseVo;
    }


    @Override
    public List<Map<String, Object>> getTopCategory3HotAlbumList(Long category1Id) {
        try {
        // 调用album微服务，根据一级分类查找三级分类
        List<BaseCategory3> baseCategory3List = albumFeignClient.findTopBaseCategory3(category1Id).getData();

        //获取三级分类id的集合
        List<Long> allCategory3Id = baseCategory3List.stream().map(baseCategory3 -> baseCategory3.getId()).collect(Collectors.toList());

        // 根据id获取三级分类
        Map<Long, BaseCategory3> baseCategory3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, value -> value));

            List<FieldValue> fieldValueList = allCategory3Id.stream().map(aLong -> {
            return FieldValue.of(aLong);
        }).collect(Collectors.toList());

            // 编写DSL语句查询指定一级分类下热门排行专辑
            SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(
                    s -> s.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id").terms(te -> te.value(fieldValueList))))
                            .size(0)
                            .aggregations("category3Agg", a -> a
                                    .terms(t -> t.field("category3Id")
                                            .size(10))
                                    .aggregations("top6Agg", as -> as.topHits(t -> t.size(6).sort(sort -> sort.field(f -> f.field("hotScore").order(SortOrder.Desc)))))
                            )
                    , AlbumInfoIndex.class);

            // 解析返回数据并封装
            Aggregate category3Agg = searchResponse.aggregations().get("category3Agg");

            Buckets<LongTermsBucket> buckets = category3Agg.lterms().buckets();
            List<LongTermsBucket> bucketList = buckets.array();

            if(CollectionUtil.isNotEmpty(bucketList)){

                List<Map<String, Object>> resultMap = bucketList.stream().map(bucket -> {
                    Map<String, Object> stringObjectHashMap = new HashMap<>();
                    stringObjectHashMap.put("baseCategory3", baseCategory3Map.get(bucket.key()));
                    Aggregate top6Agg = bucket.aggregations().get("top6Agg");
                    List<Hit<JsonData>> hits = top6Agg.topHits().hits().hits();
                    if (CollectionUtil.isNotEmpty(hits)) {
                        List<AlbumInfoIndex> collect = hits.stream().map(hit -> {
                            JsonData source = hit.source();
                            return JSON.parseObject(source.toString(), AlbumInfoIndex.class);
                        }).collect(Collectors.toList());

                        stringObjectHashMap.put("list", collect);
                    }
                    return stringObjectHashMap;
                }).collect(Collectors.toList());

                return resultMap;
            }

        } catch (Exception e) {
            log.error("[检索服务]首页热门专辑异常：{}", e);
            throw new RuntimeException(e);
        }


        return null;
    }

    private AlbumSearchResponseVo parseRuslt(SearchResponse<AlbumInfoIndex> response,AlbumIndexQuery query) {

        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();

        long total = response.hits().total().value();
        albumSearchResponseVo.setTotal(total);
        albumSearchResponseVo.setPageNo(query.getPageNo());
        albumSearchResponseVo.setPageSize(query.getPageSize());

        long totalPages = total % query.getPageSize() == 0 ? total / query.getPageSize() : total / query.getPageSize() + 1;
        albumSearchResponseVo.setTotalPages(totalPages);


        List<Hit<AlbumInfoIndex>> hits = response.hits().hits();


        if(CollectionUtil.isNotEmpty(hits)){

            List<AlbumInfoIndexVo> albumInfoIndexVoList = hits.stream().map(hit -> {
                AlbumInfoIndexVo albumInfoIndexVo = BeanUtil.copyProperties(hit.source(), AlbumInfoIndexVo.class);
                // 处理高亮部分
                Map<String, List<String>> highlightMap = hit.highlight();
                if(CollectionUtil.isNotEmpty(highlightMap) && highlightMap.containsKey("albumTitle")){
                    String highlightAlbumTitle = highlightMap.get("albumTitle").get(0);
                    albumInfoIndexVo.setAlbumTitle(highlightAlbumTitle);
                }
                return albumInfoIndexVo;
            }).collect(Collectors.toList());

            albumSearchResponseVo.setList(albumInfoIndexVoList);
        }


        return albumSearchResponseVo;
    }

    private SearchRequest buildDSL(AlbumIndexQuery albumIndexQuery) {

        //1.创建检索请求构建器对象-封装检索索引库 及 所有检索DSL语句
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index(ES_INDEX);

        //2.设置请求体参数"query",处理查询条件（关键字、分类、标签）
        //2.1 创建最外层bool组合条件对象
        BoolQuery.Builder allBool = new BoolQuery.Builder();

        // 2.2 处理关键字查询条件 采用must必须满足，包含bool组合三个子条件，三个子条件或者关系
        String keyword = albumIndexQuery.getKeyword();
        if(StringUtils.isNotBlank(keyword)){
            BoolQuery.Builder keywordBool = new BoolQuery.Builder();
            keywordBool.should(s -> s.match(m -> m.field("albumTitle").query(keyword)));
            keywordBool.should(s -> s.match(m -> m.field("albumIntro").query(keyword)));
            keywordBool.should(s -> s.term(t -> t.field("announcerName").value(keyword)));

            allBool.must(keywordBool.build()._toQuery());
        }


        //2.3 处理分类ID查询条件
        Long category1Id = albumIndexQuery.getCategory1Id();
        Long category2Id = albumIndexQuery.getCategory2Id();
        Long category3Id = albumIndexQuery.getCategory3Id();

        if(category1Id != null){
            allBool.filter(f -> f.term(t -> t.field("category1Id").value(category1Id)));
        }
        if(category2Id != null){
            allBool.filter(f -> f.term(t -> t.field("category2Id").value(category2Id)));
        }
        if(category3Id != null){
            allBool.filter(f -> f.term(t -> t.field("category3Id").value(category3Id)));
        }

        //2.4 处理标签查询条件(可能有多个)
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if(CollectionUtil.isNotEmpty(attributeList)){
            for (String attr : attributeList) {
                String[] split = attr.split(":");
                if (split != null && split.length == 2) {
                    allBool.filter(f -> f.nested(n -> n.path("attributeValueIndexList").query(
                            q -> q.bool(b -> b.must(m -> m.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0]))).must(
                                    m -> m.term(t -> t.field("attributeValueIndexList.valueId").value(split[1]))
                            ))
                    )));
                }
            }
        }

        //2.5 将最外层bool组合条件对象设置到请求体参数"query"中
        builder.query(allBool.build()._toQuery());

        //3.设置请求体参数"from","size" 处理分页
        int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        builder.from(from).size(albumIndexQuery.getPageSize());

        //4.设置请求体参数"sort" 处理排序（动态 综合、播放量、发布时间）
        //4.1 判断参数排序是否提交 提交形式： 排序字段（1：综合 2：播放量 3：发布时间）:排序方式
        String order = albumIndexQuery.getOrder();
        if (StringUtils.isNotBlank(order)) {
            //4.2 按照冒号对查询条件进行分割得到数组
            String[] split = order.split(":");
            if (split != null && split.length == 2) {
                //4.3 判断得到排序字段
                String orderField = "";
                switch (split[0]) {
                    case "1":
                        orderField = "hotScore";
                        break;
                    case "2":
                        orderField = "playStatNum";
                        break;
                    case "3":
                        orderField = "createTime";
                        break;
                }
                //4.4 设置排序
                String finalOrderField = orderField;
                builder.sort(s -> s.field(f -> f.field(finalOrderField).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }

        //5.设置请求体参数"highlight" 处理高亮，前提：用户录入关键字
        if (StringUtils.isNotBlank(keyword)) {
            builder.highlight(h -> h.fields("albumTitle", hf -> hf.preTags("<font style='color:red'>").postTags("</font>")));
        }

        //6.设置请求体参数"_source" 处理字段指定
        builder.source(s -> s.filter(f -> f.excludes("category1Id",
                "category2Id",
                "category3Id",
                "attributeValueIndexList.attributeId",
                "attributeValueIndexList.valueId")));
        return builder.build();
    }



    @Autowired
    private RedissonClient redissonClient;


    @Override
    public Map<String, Object> getAlbumInfoDetail(Long albumId) {

        // 获取布隆过滤器
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        boolean contains = bloomFilter.contains(albumId);
        if(!contains){
            throw new GuiguException(400,"小瘪三,还想玩缓存击穿?");
        }


        // 封装结果集必须使用ConcurrentHashMap 否者会出现线程安全问题
        ConcurrentHashMap<String, Object> hashMap = new ConcurrentHashMap<>();

        // 查询专辑详细信息并封装
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
            Assert.notNull(albumInfo, "专辑信息不存在,专辑ID:{}", albumId);
            hashMap.put("albumInfo", albumInfo);
            return albumInfo;
        }, threadPoolExecutor);

        // 远程调用专辑服务获取专辑统计信息-封装albumStatVo属性
        CompletableFuture<Void> albumStatVoCompletableFuture = CompletableFuture.runAsync(() -> {
            AlbumStatVo albumStatVo = albumFeignClient.getAlbumStatVo(albumId).getData();
            Assert.notNull(albumStatVo, "专辑统计不存在,专辑ID:{}", albumId);
            hashMap.put("albumStatVo", albumStatVo);
        }, threadPoolExecutor);

        // 远程调用专辑服务获取专辑分类信息-封装baseCategoryView属性
        CompletableFuture<Void> baseCategoryViewCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync((albumInfo) -> {
            BaseCategoryView baseCategoryView = albumFeignClient.getCategoryView(albumInfo.getCategory3Id()).getData();
            Assert.notNull(baseCategoryView, "专辑分类信息不存在,专辑ID:{}", albumId);
            hashMap.put("baseCategoryView", baseCategoryView);
        }, threadPoolExecutor);

        // 远程调用用户服务获取主播信息-封装announcer属性
        CompletableFuture<Void> userInfoVoCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(albumInfo.getUserId()).getData();
            Assert.notNull(userInfoVo, "主播信息不存在,主播ID:{}", albumInfo.getUserId());
            hashMap.put("announcer", userInfoVo);
        }, threadPoolExecutor);

        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                albumStatVoCompletableFuture,
                baseCategoryViewCompletableFuture,
                userInfoVoCompletableFuture
        ).join();

        return hashMap;
    }
}
























